package sk.naive.talker.command;

import sk.naive.talker.*;
import sk.naive.talker.MailHelper;
import sk.naive.talker.adapter.TagConsts;
import sk.naive.talker.message.DefaultMessageFactory;
import sk.naive.talker.util.Utils;

import javax.mail.*;
import javax.mail.Message;
import javax.mail.internet.*;
import java.rmi.RemoteException;
import java.io.IOException;
import java.util.Map;

/**
 * Mail read - shows selected message.
 *
 * @author <a href="mailto:virgo@naive.deepblue.sk">Richard "Virgo" Richter</a>
 * @version $Revision: 1.9 $ $Date: 2005/01/25 21:56:37 $
 */
public class MailRead extends AbstractCommand {
	public void exec()
		throws CommandException,
		RemoteException
	{
		try {
			MailHelper mailHelper = (MailHelper) getTalker().getProperties().get(MailHelper.TPROP_MAIL_HELPER);
			Folder folder = mailHelper.getInbox(user);
			int msgNum = -1;
			if (params == null || params.length() == 0 || "new".startsWith(params.toLowerCase())) {
				Message[] msgs = folder.getMessages();
				for (int i = 0; i < msgs.length; i++) {
					if (!msgs[i].isSet(Flags.Flag.SEEN)) {
						msgNum = msgs[i].getMessageNumber();
						break;
					}
				}
				if (msgNum == -1) {
					sendHelper().sendMessage(user, "mailRead.noUnreadMessage");
					return;
				}
			} else {
				msgNum = Integer.parseInt(params);
				if (msgNum > folder.getMessageCount() || msgNum < 1) {
					sendHelper().sendMessage(user, "mail.invalidMsgNumber");
					return;
				}
			}
			Message msg = folder.getMessage(msgNum);
			user.send(new MessageHelper(mailHelper, user, msg).toString());
			msg.setFlag(Flags.Flag.SEEN, true);
			folder.close(false);
		} catch (NumberFormatException e) {
			sendMisusageWarning();
		} catch (AuthenticationFailedException e) {
			sendHelper().sendMessage(user, "mail.authenticationFailed");
		} catch (IOException e) {
			Utils.unexpectedExceptionWarning(e);
			sendHelper().sendMessage(user, "mail.ioError");
		} catch (MessagingException e) {
			throw new CommandException(e);
		}
	}

	// TODO preco je v novych pluginoch nutny tento prostrednik medzi inner a protected? :-)))
	protected Talker getTalker() {
		return super.getTalker();
	}

	protected void ctxSet(String ctxKey, Object value) {
		super.ctxSet(ctxKey, value);
	}

	private class MessageHelper {
		private int level = 0;

		private StringBuilder buffer = new StringBuilder();
		private MailHelper mailHelper;
		private User user;

		public MessageHelper(MailHelper mailHelper, User user, Message message) throws MessagingException, IOException {
			this.mailHelper = mailHelper;
			this.user = user;
			formatPart(message);
			buffer.append(Utils.tag(TagConsts.PAGING));
		}

		public void formatPart(Part part) throws MessagingException, IOException {
			if (part instanceof Message) {
				formatEnvelope((Message) part);
			}

			if (level > 0) {
				append("mailRead.part.header", String.valueOf(level));
			}

			if (!part.isMimeType("text/plain")) {
				String contentType = part.getContentType();
				try {
					append("mailRead.part.contentType", new ContentType(contentType).toString());
				} catch (ParseException pex) {
					append("mailRead.part.unknownContentType", contentType);
				}
			}
			String filename = part.getFileName();
			if (filename != null) {
				append("mailRead.part.filename", Utils.quote(filename));
			}

			if (part.isMimeType("text/plain")) {
				append(null, Utils.quote(part.getContent().toString()));
			} else if (part.isMimeType("multipart/*")) {
				Multipart mp = (Multipart) part.getContent();
				level++;
				for (int i = 0; i < mp.getCount(); i++) {
					formatPart(mp.getBodyPart(i));
				}
				level--;
			} else if (part.isMimeType("message/rfc822")) {
				level++;
				formatPart((Part) part.getContent());
				level--;
			} else {
				/* TODO premysliet co s binarnym a neznamym obsahom
				Object o = part.getContent();
				if (o instanceof String) {
					pr("This is a string");
					pr("---------------------------");
					vypisat ((String) o);
				} else if (o instanceof InputStream) {
					pr("This is just an input stream");
					pr("---------------------------");
					InputStream is = (InputStream) o;
					int c;
					while ((c = is.read()) != -1)
						vypisat (c);
				} else {
				}
				*/
			}
		}

		private void formatEnvelope(Message message) throws MessagingException {
			append("mailRead.envelope.number", new Integer(message.getMessageNumber()));
			dumpAddresses(message.getFrom(), "mailRead.envelope.from", false);
			dumpAddresses(message.getRecipients(Message.RecipientType.TO), "mailRead.envelope.to", true);
			dumpAddresses(message.getRecipients(Message.RecipientType.CC), "mailRead.envelope.cc", false);
			if (message.getSubject() != null && message.getSubject().length() != 0) {
				append("mailRead.envelope.subject", Utils.quote(message.getSubject()));
			}
			if (message.getSentDate() != null) {
				append("mailRead.envelope.sendDate", message.getSentDate());
			}
			if (message.getSentDate() == null && message.getReceivedDate() != null) {
				append("mailRead.envelope.receivedDate", message.getReceivedDate());
			}
			append("mailRead.envelope.separator", null);
		}

		private void dumpAddresses(Address[] addresses, String resourceKey, boolean testSelf) {
			if (addresses != null) {
				if (testSelf && containsOnlyUser(addresses)) {
					return;
				}
				for (int i = 0; i < addresses.length; i++) {
					String address = Utils.quote(addresses[i].toString());
					if (address.endsWith(mailHelper.getTransportHost())) {
						User aUser = MailRead.this.getTalker().userFinder().findUserByLogin(address.substring(0, address.indexOf('@')));
						if (aUser != null) {
							address = MailRead.this.getString("userName", aUser.getProperties());
						}
					}
					append(resourceKey, address);
				}
			}
		}

		private boolean containsOnlyUser(Address[] addresses) {
			return addresses != null
				&& addresses.length == 1
				&& addresses[0].toString().equalsIgnoreCase(mailHelper.createStoreAddress(user.getLogin()));
		}

		private void append(String resourceKey, Object value) {
			if (resourceKey != null) {
				if (value != null) {
					ctxSet(DefaultMessageFactory.CTXKEY_VAL, value);
				}
				buffer.append(getString(resourceKey, user.getProperties()));
			} else {
				buffer.append(value.toString());
			}
		}

		public String toString() {
			return buffer.toString();
		}
	}

	protected String getString(String key, Map ctx) {
		return super.getString(key, ctx);
	}
}
